/*
 * file name:mal_service.c
 * version :v1.0.1
 * Change Logs:
 * Date             Author      	main change
 * 2024-11-03     	lanxin          the first version
 * 2025-03-31     	lanxin          add example comment
 *
*/

/********************************************* READ ME BEGIN *************************************************************/

/* Brief:
*
* *1.用于解耦驱动与应用的中间层，其实现类似于 rt_device。
*
*/

/* Notice:
*
* *1.无互斥保护，注意调用时的资源保护。
*
* *2.先注册 mal_service_register(),在调用其他函数。
*
*/

/*
 * *example:
*/

// typedef struct pwm_manage
// {
// 	s_service_t srv;
// } s_pwm_manage_t;

// static s_pwm_manage_t pm =
// {
// 	.srv.name = SERVICE_NAME_PWM,
// };

// static int srv_pm_init ( const struct service *srv, void *argv )
// {
// 	return 0;
// }

// static int srv_pm_stop ( const struct service *srv )
// {
// 	return 0;
// }

// static int srv_pm_read ( const struct service *srv, int pos, void *p_read, int read_size )
// {
// 	return 0;
// }

// static int srv_pm_write ( const struct service *srv, int pos, const void *p_write, int write_size )
// {
// 	return 0;
// }

// static int srv_pm_control ( const struct service *srv, int cmd, void *argv )
// {
// 	return -1;
// }

// static int register_srv_pm_service ( void )
// {
// 	pm.srv.init = srv_pm_init;
// 	pm.srv.stop = srv_pm_stop;
// 	pm.srv.read = srv_pm_read;
// 	pm.srv.write = srv_pm_write;
// 	pm.srv.control = srv_pm_control;

// 	mal_service_register ( &pm.srv );

// 	return 0;
// }

// /* Export to auto initial table */
// INIT_BOARD_EXPORT ( register_srv_pm_service );

/********************************************* READ ME END ***************************************************************/

/* source file */
#include "mal_service.h"

/* private define */
#define FS_ASSERT(PARA)                            if((PARA) == 0) { rt_kprintf("file:%s",__FILE__);RT_ASSERT(0);}
#define FS_PARA_CHECK_NULL(PARA)                   if((PARA) == 0) {rt_kprintf("file:%s line:%d para is null\r\n",__FILE__,__LINE__); return;}
#define FS_PARA_CHECK_NULL_THEN_RETURN(PARA,VALUE) if((PARA) == 0) {rt_kprintf("file:%s line:%d para is null\r\n",__FILE__,__LINE__); return VALUE;}

/* variable declaration */
static rt_list_t list_srv_head = RT_LIST_OBJECT_INIT ( list_srv_head );

/* function declaration */

static int mal_service_show ( void )
{
	if ( rt_list_isempty ( &list_srv_head ) )
	{
		rt_kprintf ( "there is no service\r\n" );
		return 0;
	}

	s_service_t *srv = 0;
	rt_list_t *tmp = 0;
	rt_list_for_each ( tmp, &list_srv_head )
	{
		srv = rt_list_entry ( tmp, s_service_t, list_srv );

		if ( srv )
			rt_kprintf ( "service [%s]\r\n", srv->name );
	}

	return 0;
}

SRV_PUT_TO_RAM const s_service_t *mal_service_find ( const char *name )
{
	if ( name == 0 || ( rt_list_len ( &list_srv_head ) == 0 ) )
		goto err;

	s_service_t *srv = 0;
	rt_list_t *tmp = 0;
	rt_list_for_each ( tmp, &list_srv_head )
	{
		srv = rt_list_entry ( tmp, s_service_t, list_srv );

		if ( srv && ( rt_strcmp ( name, srv->name ) == 0 ) )
			return ( const s_service_t * ) srv;
	}

err:
	rt_kprintf ( "can not find service [%s]\r\n", name == 0 ? "err para" : name );
	return 0;
}

SRV_PUT_TO_RAM int mal_service_init ( const s_service_t *srv, void *argv )
{
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv, -1 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv->init, -1 );

	return srv->init ( srv, argv );
}

SRV_PUT_TO_RAM int mal_service_init_by_name ( const char *name, void *argv )
{
	return mal_service_init ( mal_service_find ( name ), argv );
}

SRV_PUT_TO_RAM int mal_service_read ( const s_service_t *srv, int pos, void *p_read, int read_size )
{
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv, 0 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv->read, 0 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( p_read, 0 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( read_size, 0 );

	return srv->read ( srv, pos, p_read, read_size );
}

SRV_PUT_TO_RAM int mal_service_read_by_name ( const char *name, int pos, void *p_read, int read_size )
{
	return mal_service_read ( mal_service_find ( name ), pos, p_read, read_size );
}

SRV_PUT_TO_RAM int mal_service_write ( const s_service_t *srv, int pos, const void *p_write, int write_size )
{
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv, 0 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv->write, 0 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( p_write, 0 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( write_size, 0 );

	return srv->write ( srv, pos, p_write, write_size );
}

SRV_PUT_TO_RAM int mal_service_write_by_name ( const char *name, int pos, const void *p_write, int write_size )
{
	return mal_service_write ( mal_service_find ( name ), pos, p_write, write_size );
}

SRV_PUT_TO_RAM int mal_service_stop ( const s_service_t *srv )
{
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv, -1 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv->stop, -1 );

	return srv->stop ( srv );
}

SRV_PUT_TO_RAM int mal_service_stop_by_name ( const char *name )
{
	return mal_service_stop ( mal_service_find ( name ) );
}

SRV_PUT_TO_RAM void mal_service_stop_all ( void )
{
	if ( rt_list_len ( &list_srv_head ) == 0 )
	{
		rt_kprintf ( "no service need to stop\r\n" );
		return;
	}

	rt_list_t *tmp = 0;
	s_service_t *srv = 0;
	rt_list_for_each ( tmp, &list_srv_head )
	{
		srv = rt_list_entry ( tmp, s_service_t, list_srv );

		if ( srv && srv->stop )
		{
			int res = srv->stop ( srv );
			rt_kprintf ( "stop service [%s] %s\r\n", srv->name, res == 0 ? "succeed" : "failed" );
		}
	}
}

SRV_PUT_TO_RAM int mal_service_control ( const s_service_t *srv, int cmd, void *argv )
{
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv, -1 );
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv->control, -1 );

	return srv->control ( srv, cmd, argv );
}

SRV_PUT_TO_RAM int mal_service_control_by_name ( const char *name, int cmd, void *argv )
{
	return mal_service_control ( mal_service_find ( name ), cmd, argv );
}

SRV_PUT_TO_RAM void mal_service_set_usr_data ( const s_service_t *srv, void *usr_data )
{
	FS_PARA_CHECK_NULL ( srv );
	s_service_t *p_srv = ( s_service_t * ) srv;

	if ( p_srv )
		p_srv->usr_data = usr_data;
}

SRV_PUT_TO_RAM void mal_service_set_usr_data_by_name ( const char *name, void *usr_data )
{
	mal_service_set_usr_data ( mal_service_find ( name ), usr_data );
}

SRV_PUT_TO_RAM void mal_service_set_usr_cb ( const s_service_t *srv, usr_cb_t usr_cb )
{
	FS_PARA_CHECK_NULL ( srv );
	s_service_t *p_srv = ( s_service_t * ) srv;

	if ( p_srv )
		p_srv->usr_cb = usr_cb;
}

SRV_PUT_TO_RAM void mal_service_set_usr_cb_by_name ( const char *name, usr_cb_t usr_cb )
{
	mal_service_set_usr_cb ( mal_service_find ( name ), usr_cb );
}

int mal_service_register ( s_service_t *srv )
{
	FS_PARA_CHECK_NULL_THEN_RETURN ( srv, -1 );

	rt_list_init ( &srv->list_srv );
	rt_list_insert_after ( &list_srv_head, &srv->list_srv );

	return 0;
}

/* 导出到初始化列表 */

/* 导出到 MSH 命令列表 */
MSH_CMD_EXPORT ( mal_service_show, show service );
